Python-RegEx(正则表达式)

关于Python的正则表达式,初步学习了下,感觉跟shell脚本的正则表达式大体相同,先来做个小结吧!

正则表达式

正则表达式在实际的文本文件处理中,经常用到,其实正则表达式并不是Python的一部分,其它语言中都有。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能真的十分强大。得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同;但不用担心,不被支持的语法通常是不常用的部分。如果已经在其他语言里使用过正则表达式,只需要简单看一看就可以上手了。

下图展示了使用正则表达式进行匹配的流程:

从上图我们可以看出,正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,来看看下面的这个正则表达式模式。

ID 模式 描述
1 ^ 匹配字符串的开头
2 $ 匹配字符串的末尾。
3 . 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
4 […] 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,’m’或’k’
5 [^…] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
6 * 匹配0个或多个的表达式。
7 + 匹配1个或多个的表达式。
8 ? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
9 { n,} 精确匹配n个前面表达式。
10 {n,m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
11 (re) G匹配括号内的表达式,也表示一个组
12 (?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
13 (?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
14 (?:re) 类似 (…), 但是不表示一个组
15 (?imx:re) 在括号中使用i, m, 或 x 可选标志
16 (?-imx:re) 在括号中不使用i, m, 或 x 可选标志
17 (?#…) 注释.
18 (?=re) 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
19 (?!re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
20 (?>re) 匹配的独立模式,省去回溯。
21 \w 匹配字母数字,等价于’[A-Za-z0-9_]’
22 \W 匹配非字母数字, [^A-Za-z0-9_]’
23 \s 匹配任意空白字符,等价于[\t\n\r\f].
24 \S 匹配任意非空字符,等价于[^ \f\n\r\t\v]
25 \d 匹配任意数字,等价于[0-9].
26 \D 匹配任意非数字,等价于[^0-9]。
27 \A 匹配字符串开始
28 \Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
29 \z 匹配字符串结束
30 \G 匹配最后匹配完成的位置。
31 \b 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
32 \B 匹配非单词边界。’er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
33 \n, \t, 等. 匹配一个换行符。匹配一个制表符。等
34 \1…\9 匹配第n个分组的子表达式。
35 \10 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。

下面从正则表达式的几个函数/方法来简单介绍下正则表达式的用法。


re.match()函数

re.match 尝试从字符串的开头匹配一个模式,如:下面的例子匹配第一个单词。

1
2
3
4
5
6
7
import re
text = "This is a very beautiful girl, I like her very much."
m = re.match(r"(\w+)\s", text)
if m:
print m.group(0), '\n', m.group(1)
else:
print 'not match'

输出:


This
This

re.match的函数原型为:re.match(pattern, string, flags)

  • 第一个参数是正则表达式,这里为”(\w+)\s”,如果匹配成功,则返回一个Match,否则返回一个None;
  • 第二个参数表示要匹配的字符串;
  • 第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

re.search()函数

re.search函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。

1
2
3
4
5
6
7
import re
text = "This is a very beautiful girl, I like her very much."
m = re.search(r'\sbeaut(i)ful\s', text)
if m:
print m.group(0), m.group(1)
else:
print 'not search'

输出结果:


beautiful i

re.search的函数原型为: re.search(pattern, string, flags)

每个参数的含意与re.match一样。


re.match()与re.search()的区别

re.match只匹配字符串的开始,如果字符串从一开始就不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

请看下面这个实例:

1
2
3
4
5
6
7
import re
line = "This is a very beautiful girl, I like her very much.";
m = re.match( r'girl', line, re.M|re.I)
if m:
print "match --> m.group() : ", m.group()
else:
print "No match!!"

match会从字符串起始出进行模式匹配,即模式中的其实字母‘g’匹配‘This’中的‘T’,所以,匹配失败。

No match!!

如果使用的是search,来看看结果:

1
2
3
4
5
m = re.search( r'girl', line, re.M|re.I)
if m:
print "search --> m.group() : ", m.group()
else:
print "No match!"

以上实例运行结果如下:

search --> m.group() :  girl

re.sub() & re.subn()函数

re.sub用于替换字符串中的匹配项。下面一个例子将字符串中的空格 ‘ ‘ 替换成 ‘-‘ :

1
2
3
import re
text = "I like Cats more than dogs!"
print re.sub(r'\s+', '-', text)

输出:


I-like-Cats-more-than-dogs!

re.sub的函数原型为:re.sub(pattern, repl, string, count)

其中第二个函数是替换后的字符串;本例中为’-‘

第四个参数指替换个数。默认为0,表示每个匹配项都替换。

re.sub还允许使用函数对匹配项的替换进行复杂的处理。如:re.sub(r’\s’, lambda m: ‘[‘ + m.group(0) + ‘]’, text, 0);将字符串中的空格’ ‘替换为’[ ]’。

注:re.subn和re.sub大体相似,唯一不同的就是返回结果,subn会将匹配的个数也显示出来。

如:

1
2
3
4
5
>>>import re
>>>text = "I like Cats more than dogs!"
>>>print re.subn(r'\s+', '-', text)

('I-like-Cats-more-than-dogs!', 5)

re.split()函数

可以使用re.split来分割字符串,如:re.split(r’-‘, text);将字符串按’-‘符号分割成一个单词列表。

1
2
3
import re
text="I-really-like-this-girl!"
re.split(r'-',text)

输出:


['I', 'really', 'like', 'this', 'girl!']

re.findall()函数

re.findall可以获取字符串中所有匹配的字符串。如:re.findall(r’\w*i\w*‘, text);获取字符串中,包含’oo’的所有单词。

1
2
3
import re
text="I-really-like-this-girl!"
re.findall(r'girl',text)

输出结果:

['like', 'this', 'girl']

re.compile()函数

可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式对象的一个例子:

1
2
3
4
5
6
7
8
import re
regex = re.compile(r'\w*er\w*') # 将正则表达式编译成Pattern对象
text = "This is a very beautiful girl, I like her very much."
m = regex.search(text) #使用regex来匹配text字符串
if m:
print m.group() # 使用Match获得分组信息
print regex.findall(text) #查找所有包含'oo'的单词
print regex.sub(lambda m: '[' + m.group(0) + ']', text) #将字符串中含有'oo'的单词用[]括起来。

分别输出下列信息:

'very'
['very', 'her', 'very']
This is a [very] beautiful girl, I like [her] [very] much.

邮箱验证

使用Python写一个简单的邮箱验证的正则表达式:

根据csu.ldw@csu.edu.cn来填写规则

规则:

  • @前面可以有’.’, ‘_’, ‘-‘, 但不能出现在头尾,而且不能连续出现
  • @后面到结尾之间,可以有多个子域名
  • 邮箱的结尾为2~5个字母,比如cn、com、name等
1
2
3
4
5
6
7
8
9
10
11
12
#-*- coding: utf-8 -*-
"""
Created on Thu Oct 29 20:28:57 2015
@author: liudiwei
"""
import re
regex = re.compile('^[A-Za-z0-9]+(([\.\_\-])?[A-Za-z0-9]+)+@([A-Za-z]+.)+[A-Za-z]{2,5}$')
m = regex.match("csu.ldw@csu.edu.cn")
if m:
print m.group()
else:
print "no match!"

测试输出:

csu.ldw@csu.edu.cn

当m = regex.match(“_csu.ldw@csu.edu.cn“)
当邮箱为:

_csu.ldw@csu.edu.cn  
csu.ldw_@csu.edu.cn
csu.ldw@csu_.edu.cn
_csu.ldw@csu.edu.cn1

都不会匹配

提示:合法邮箱的规则可能不够完善,这里就简单的匹配这三个规则吧!